/**
 * 装饰性花园(The ornamental garden)
 *
 * @author fireway
 * @since  2019年 01月 18日 星期五 06:56:15 CST
 */
package concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Count {
    private int mValue = 0;

    private Random mRandom = new Random(47);

    public synchronized int increase() {
        int temp = mValue;

        if(mRandom.nextBoolean()) {
            Thread.yield();
        }

        temp++;
        mValue = temp;

        return temp;
    }

    public synchronized int value() {
        return mValue;
    }
}

class Entrance implements Runnable {
    private final int mId;

    /**
     * 每个Entrance任务都维护一个本地值mNumber，它包含通过某个特定入口的人数
     */
    private int mNumber = 0;

    private static Count sCount = new Count();

    private static volatile boolean sCanceled = false;

    private static List<Entrance> sEntrances = new ArrayList<Entrance>();

    public Entrance(int id) {
        mId = id;
        // Keep this task in a list. Also prevents
        // garbage collection of dead tasks:
        sEntrances.add(this);
    }

    /**
     * Entrance.run()只是递增mNumber和sCount对象，然后休眠100毫秒
     */
    @Override
    public void run() {
        while (!sCanceled) {
            synchronized(this) {
                ++mNumber;
            }
            System.out.println(this + " Total: " + sCount.increase());
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch(InterruptedException e) {
                System.out.println("sleep interrupted");
            }
        }
        System.out.println("Stopping " + this);
    }

    public static void setCancel() {
        sCanceled = true;
    }

    public static int getTotalCount() {
        return sCount.value();
    }

    public static int sumEntrances() {
        int sum = 0;

        for(Entrance entrance : sEntrances) {
            sum += entrance.getNumber();
        }

        return sum;
    }

    private synchronized int getNumber() {
        return mNumber;
    }

    @Override
    public String toString() {
        return "Entrance " + mId + ": " + getNumber();
    }
}

public class OrnamentalGarden {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i = 0; i < 5; i++)  {
            exec.execute(new Entrance(i));
        }

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 这个程序以稳定的方式关闭所有事物方面还有一些小麻烦，
        // 其部分原因是为了说明在终止多线程程序时你必须相当小心
        Entrance.setCancel();
        exec.shutdown();
        try {
            if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS)) {
                System.out.println("Some tasks were not terminated!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Total: " + Entrance.getTotalCount());
        System.out.println("Sum of Entrances: " + Entrance.sumEntrances());
    }
}
